package com.itheima.activiti.service.activiti.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.itheima.activiti.auth.JwtContextUtils;
import com.itheima.activiti.constant.ListenerConstant;
import com.itheima.activiti.dragram.ActivitiProcessDiagramGenerator;
import com.itheima.activiti.dto.activiti.CompleteDTO;
import com.itheima.activiti.dto.activiti.ProcessActivityDTO;
import com.itheima.activiti.dto.activiti.RejectDTO;
import com.itheima.activiti.dto.activiti.TaskDTO;
import com.itheima.activiti.dto.dto.HistoryDetailDTO;
import com.itheima.activiti.dto.system.UserDTO;
import com.itheima.activiti.service.activiti.AssignmentService;
import com.itheima.activiti.service.system.UserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AssignmentServiceImpl implements AssignmentService {
    @Autowired
    private org.activiti.engine.TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private UserService userService;

    @Override
    public void recall(String taskId, String comment) {
        String user = JwtContextUtils.getUser().getId().toString();
        // 获取任务信息
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String currActivityId = task.getTaskDefinitionKey();

        String processDefinitionId = task.getProcessDefinitionId();
        String processInstanceId = task.getProcessInstanceId();

        // 获取撤回节点
        HistoricTaskInstance currTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).taskAssignee(user).list().get(0);
        String targetActivityId = currTask.getTaskDefinitionKey();

        // 改变流程路线
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getMainProcess();
        FlowNode targetFlow = (FlowNode) process.getFlowElement(targetActivityId);

        // 记录原活动方向
        FlowNode currFlow = (FlowNode) process.getFlowElement(currActivityId);

        List<SequenceFlow> oldSequenceFlows = Lists.newArrayList();
        oldSequenceFlows.addAll(currFlow.getOutgoingFlows());

        List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        newSequenceFlow.setId(uuid);
        newSequenceFlow.setSourceFlowElement(currFlow);// 原节点
        newSequenceFlow.setTargetFlowElement(targetFlow);// 目标节点
        newSequenceFlow.setSourceRef(currFlow.getId());
        newSequenceFlow.setTargetRef(targetFlow.getId());
        newSequenceFlows.add(newSequenceFlow);

        currFlow.setOutgoingFlows(newSequenceFlows);

        // 完成当前任务....
        taskService.addComment(taskId, null, comment);
        taskService.setVariable(taskId, ListenerConstant.OPERATE, ListenerConstant.RECALL);
        taskService.complete(taskId);
        Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 设置执行人
        if (nextTask != null) {
            taskService.setAssignee(nextTask.getId(), user);
        }
        //恢复原方向
        currFlow.setOutgoingFlows(oldSequenceFlows);
    }

    @Override
    public void terminate(String taskId, String comment) {
        String user = JwtContextUtils.getUser().getId().toString();
        // 根据任务id获取任务信息
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String currActivityId = task.getTaskDefinitionKey();
        String processDefinitionId = task.getProcessDefinitionId();

        // 获取终止的节点  最后的完成节点
        FlowNode targetFlow = null;
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getMainProcess();
        Object[] flowElements = process.getFlowElements().toArray();
        for (Object object : flowElements) {
            log.debug(object.getClass() + "");
            if (object.getClass().getSimpleName().equals("EndEvent")) {
                targetFlow = (FlowNode) object;
            }
        }

        FlowNode currFlow = (FlowNode) process.getFlowElement(currActivityId);

        // 记录原活动方向
        List<SequenceFlow> oldSequenceFlows = Lists.newArrayList();
        oldSequenceFlows.addAll(currFlow.getOutgoingFlows());

        List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        newSequenceFlow.setId(uuid);
        newSequenceFlow.setSourceFlowElement(currFlow);// 原节点
        newSequenceFlow.setTargetFlowElement(targetFlow);// 目标节点
        newSequenceFlow.setSourceRef(currFlow.getId());
        newSequenceFlow.setTargetRef(targetFlow.getId());
        newSequenceFlows.add(newSequenceFlow);

        currFlow.setOutgoingFlows(newSequenceFlows);

        // 完成任务....
        taskService.setAssignee(taskId, user);
        taskService.addComment(taskId, null, comment);
        taskService.setVariable(taskId, ListenerConstant.OPERATE, ListenerConstant.TERMINATE);
        taskService.complete(taskId);

        //恢复原方向
        currFlow.setOutgoingFlows(oldSequenceFlows);
    }

    @Override
    public Page<TaskDTO> queryToDoTasks(String taskName, String processDefinationName, int page, int pageSize) {
//        1.  分页查找所有任务，执行人为当前登录用户
        String userId = JwtContextUtils.getUser().getId().toString();
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(userId);

//        2.  如果前端传入任务名称，查找条件需要加上任务名称
        if (StringUtils.isNotEmpty(taskName)) {
            taskQuery.taskName(taskName);
        }
        List<Task> tasks = taskQuery.listPage((page - 1) * pageSize, pageSize);

//        3. 查找任务的流程定义，则查询条件中需要加上此名称
        List<TaskDTO> dtoList = tasks.stream().map(item -> {
            TaskDTO dto = new TaskDTO();
            //任务相关属性
            dto.setTaskId(item.getId());
            dto.setTaskName(item.getName());
            dto.setCreateTime(item.getCreateTime());

            //获取流程定义id
            String pdid = item.getProcessDefinitionId();
            //查询条件中加入流程定义的id
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(pdid);
            //如果前端传入的流程定义名称不为空
            if (StringUtils.isNotEmpty(processDefinationName)) {
                //查询条件中插入流程定义名称
                query.processDefinitionName(processDefinationName);
            }

            //执行流程定义查询
            ProcessDefinition processDefinition = query.singleResult();

            //如果查询不到流程定义
            if (null == processDefinition) {
                return null;    //返回空
            } else {   //能够查询到流程定义
                //设置dto中流程定义相关的值
                dto.setProcessDefinitionKey(processDefinition.getKey());    //流程定义的key
                dto.setProcessDefinitionId(processDefinition.getId());      //流程定义的id
                dto.setProcessDefinitionName(processDefinition.getName());  //流程定义的name

                //查找流程实例
                HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(item.getProcessInstanceId())     //按流程定义id查询
                        .singleResult();
                dto.setProcessInstanceId(hpi.getId());        //流程实例的id
                dto.setStartTime(hpi.getStartTime());         //流程开始时间

                //操作需要的属性
                dto.setBusinessKey(item.getBusinessKey());    //业务表单的id
                //是否自己提交:当前用户是否是流程实例的发起人
                if (userId.equals(hpi.getStartUserId())) {
                    dto.setSelf(true);
                }

                // 4. 将返回的任务和流程定义赋值给DTO对象
                return dto;
            }
        }).collect(Collectors.toList());

        //去掉空值
        dtoList.stream().filter(item -> item != null);


//        5. 将数据返回给前端：统一返回的（R类）、分页的（Page类）、包含业务传输数据（DTO类）：R<Page<TaskDTO>>
        long total = taskQuery.count();//任务总数
        Page<TaskDTO> dtoPage = new Page(page, pageSize, total);
        dtoPage.setRecords(dtoList);

        return dtoPage;
    }

    /**
     * 查询所有已完成的任务
     *
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public Page<ProcessActivityDTO> queryDoneTasks(int page, int pageSize) {
        //获取当前用户
        String userId = JwtContextUtils.getUser().getId().toString();

        //查询当前用户已完成的历史任务实例
        HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery()  //查询历史任务实例
                .taskAssignee(userId)   //查询当前用户的
                .finished()    //查询已完成的
                .orderByHistoricTaskInstanceStartTime().desc();//按照历史任务实例开始时间进行降序排列

        //执行分页查询
        List<HistoricTaskInstance> list = query.listPage((page - 1) * pageSize, pageSize);
        //得到查询结果总数
        long total = query.count();

        //遍历查询结果
        List<ProcessActivityDTO> dtos = list.stream().map(item -> {
            //定义返回dto
            ProcessActivityDTO dto = new ProcessActivityDTO();

            //流程定义id
            String pdid = item.getProcessDefinitionId();
            //流程实例id
            String pid = item.getProcessInstanceId();

            //获取流程定义
            ProcessDefinition pd = repositoryService.getProcessDefinition(pdid);
            dto.setProcessDefinitionId(pd.getId());         //流程定义的id
            dto.setProcessDefinitionKey(pd.getKey());       //流程定义的key
            dto.setProcessDefinitionName(pd.getName());     //流程定义的name
            dto.setProcessDefinitionVersion(pd.getVersion());   //流程定义的版本号

            //获得历史流程实例
            HistoricProcessInstance hp = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(pid) //按流程实例id查询
                    .singleResult();        //返回流程实例对象
            dto.setStartTime(hp.getStartTime());        //流程开始时间
            dto.setProcessInstanceId(hp.getId());       //流程实例id
            dto.setStartUserId(hp.getStartUserId());    //发起人id
            dto.setBusinessKey(hp.getBusinessKey());    //设置业务id

            //获得发起人详细信息
            UserDTO userDTO = userService.getById(hp.getStartUserId());
            dto.setStartUserName(userDTO.getName());    //发起人姓名

            //设置任务结束时间
            dto.setEndTime(item.getEndTime());

            return dto;
        }).collect(Collectors.toList());

        //新建分页对象
        Page<ProcessActivityDTO> pageResult = new Page(page, pageSize, total);
        //设置分页结果
        pageResult.setRecords(dtos);
        return pageResult;
    }

    @Override
    public void complete(CompleteDTO completeDTO) {
        //添加备注
        taskService.addComment(completeDTO.getTaskId(), null, completeDTO.getComment());
        taskService.addComment(completeDTO.getTaskId(), null, ListenerConstant.OPERATE, ListenerConstant.AGREE);

        //设置完成状态
        taskService.complete(completeDTO.getTaskId());
    }

    @Override
    public List<com.itheima.activiti.dto.system.UserDTO> getRejectUser(String taskId) {
        String currentUser = JwtContextUtils.getUser().getId().toString();  //获取当前登录用户
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();//根据id找到当前执行的任务
        if (task == null) {// 如果流程结束 则任务为空。
            log.info("未找到任务");
            return null;
        }
        //根据流程实例的id，查找所有历史任务
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .orderByTaskCreateTime().asc().list();

        //找到历史任务的处理人
        List<String> list = historicTaskInstances.stream()
                .filter(item -> StringUtils.isNotEmpty(item.getAssignee())) //根据处理人进行过滤
                .map(HistoricTaskInstance::getAssignee) //执行HistoricTaskInstance类的getAssignee方法，找到处理人
                .collect(Collectors.toList()); //返回list集合

        List<com.itheima.activiti.dto.system.UserDTO> result = new ArrayList<>();
        // 按照时间顺序排列，只获取到当前审批人之前的用户
        for (String user : list) {
            if (currentUser.equals(user)) {
                return result;
            }
            com.itheima.activiti.dto.system.UserDTO userDTO = userService.getById(user);
            result.add(userDTO);
        }
        return result;
    }

    @SneakyThrows
    @Override
    public void reject(RejectDTO rejectDTO) {
        String currentUser = JwtContextUtils.getUser().getId().toString();
        String taskId = rejectDTO.getTaskId();
        String comment = rejectDTO.getComment();

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String currActivityId = task.getTaskDefinitionKey();

        String processDefinitionId = task.getProcessDefinitionId();
        String processInstanceId = task.getProcessInstanceId();

        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime().desc().list();

        if (CollectionUtils.isEmpty(historicTaskInstances) || historicTaskInstances.size() < 2) {
            return;
        }

        // list里的第二条代表上一个任务
        HistoricTaskInstance lastTask = historicTaskInstances.get(1);

        // 获取当前用户任务节点
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Process process = bpmnModel.getProcesses().get(0);

        FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);
        if (currFlow == null) {
            List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
            for (SubProcess subProcess : subProcessList) {
                FlowElement flowElement = subProcess.getFlowElement(currActivityId);

                if (flowElement != null) {
                    currFlow = (FlowNode) flowElement;
                    break;
                }
            }
        }

        // 记录原活动方向
        List<SequenceFlow> oldSequenceFlows = Lists.newArrayList();
        oldSequenceFlows.addAll(currFlow.getOutgoingFlows());

        // 清理活动方向
        currFlow.getOutgoingFlows().clear();

        List<SequenceFlow> newSequenceFlows = Lists.newArrayList();

        String targetActivityId = null;
        String targetUser = rejectDTO.getTargetUser();
        if (StringUtils.isEmpty(targetUser)) {
            List<HistoricTaskInstance> allHistoryTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).orderByHistoricTaskInstanceStartTime().asc().list();
            for (int i = 1; i < allHistoryTask.size(); i++) {
                HistoricTaskInstance historyTask = allHistoryTask.get(i);
                if (currentUser.equals(historyTask.getAssignee())) {
                    // 找到当前节点第一次出现的历史记录，然后返回给他的上一个节点
                    targetUser = allHistoryTask.get((i - 1)).getAssignee();
                    targetActivityId = allHistoryTask.get((i - 1)).getTaskDefinitionKey();
                    log.info("targetUser is empty user:{} targetActivityId:{}", targetUser, targetActivityId);
                    break;
                }
            }
        } else {
            HistoricTaskInstance targetTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).taskAssignee(targetUser).orderByHistoricTaskInstanceStartTime().asc().list().get(0);
            targetActivityId = targetTask.getTaskDefinitionKey();
            log.info("targetUser is not empty user:{} targetActivityId:{}", targetUser, targetActivityId);
        }


        FlowNode targetNode = (FlowNode) process.getFlowElement(targetActivityId);

        SequenceFlow newSequenceFlow = new SequenceFlow();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        newSequenceFlow.setId(uuid);
        newSequenceFlow.setSourceFlowElement(currFlow);// 原节点
        newSequenceFlow.setTargetFlowElement(targetNode);// 目标节点
        newSequenceFlow.setSourceRef(currFlow.getId());
        newSequenceFlow.setTargetRef(targetNode.getId());
        newSequenceFlows.add(newSequenceFlow);

        currFlow.setOutgoingFlows(newSequenceFlows);

        log.info("newFlow:{} ", newSequenceFlows);

        // 拒接、通过、驳回指定节点
        taskService.addComment(taskId, null, comment);
        taskService.addComment(taskId, null, ListenerConstant.OPERATE, ListenerConstant.REJECT);
        taskService.complete(taskId);
        Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 设置执行人
        if (nextTask != null) {
            taskService.setAssignee(nextTask.getId(), StringUtils.isNotEmpty(targetUser) ? targetUser : lastTask.getAssignee());
        }
        //恢复原方向
        currFlow.setOutgoingFlows(oldSequenceFlows);
    }

    @SneakyThrows
    @Override
    public InputStream getProcessInstanceDiagram(String processInstanceId) {
        HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = hpi.getProcessDefinitionId();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        ProcessDiagramGenerator diagramGenerator = new ActivitiProcessDiagramGenerator();

        //高亮环节id集合
        List<String> highLightedActivitis = getHighLightedActivitis(processInstanceId);

        //高亮线路id集合
        List<String> highLightedFlows = getHighLightedFlows(bpmnModel, processInstanceId);

        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, highLightedActivitis, highLightedFlows);

        return inputStream;
    }

    @Override
    public List<HistoryDetailDTO> historyTaskList(String processInstanceId) {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).finished().orderByHistoricActivityInstanceStartTime().asc().list();
        List<HistoryDetailDTO> historyDTOs = list.stream().filter(item -> StringUtils.isNoneBlank(item.getActivityName())).map(item -> {
            HistoryDetailDTO historyDetailDTO = new HistoryDetailDTO();
            BeanUtil.copyProperties(item, historyDetailDTO);
            historyDetailDTO.setDurationInSeconds(item.getDurationInMillis() / 1000 / 60);
            String comment = getComment(item);
            historyDetailDTO.setComment(comment);
            String userId = historyDetailDTO.getAssignee();
            com.itheima.activiti.dto.system.UserDTO userDTO = userService.getById(userId);
            historyDetailDTO.setAssignee(userDTO == null ? "" : userDTO.getName());
            return historyDetailDTO;
        }).filter(item -> item != null).collect(Collectors.toList());
        return historyDTOs;
    }

    /**
     * 组装审批意见信息
     *
     * @param item
     * @return
     */
    private String getComment(HistoricActivityInstance item) {
        String comment = null;
        List<Comment> comments = taskService.getTaskComments(item.getTaskId(), ListenerConstant.OPERATE);
        if (!CollectionUtils.isEmpty(comments) || comments.size() > 0) {
            comment = comments.get(0).getFullMessage();
        }

        comments = taskService.getTaskComments(item.getTaskId());
        if (!CollectionUtils.isEmpty(comments) && comments.size() > 0) {
            if (comment == null) {
                comment = comments.get(0).getFullMessage();
            } else {
                comment = comment + " : (" + comments.get(0).getFullMessage() + ")";
            }
        }
        return comment;
    }

    private List<String> getHighLightedActivitis(String processInstanceId) {
        List<String> highLightedActivitis = new ArrayList();

        List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime()
                .asc().list();

        for (HistoricActivityInstance tempActivity : highLightedActivitList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(processInstanceId).singleResult();
        if (null != execution) {
            highLightedActivitis.add(execution.getActivityId());
        }

        return highLightedActivitis;
    }

    /**
     * 获取需要高亮的线
     *
     * @return
     */
    private List<String> getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) {
        //因为我们这里只定义了一个Process 所以获取集合中的第一个即可 流程 process
        Process process = bpmnModel.getProcesses().get(0);

        //获取所有的FlowElement信息
        Collection<FlowElement> flowElements = process.getFlowElements();
        //声明 一个Map
        Map<String, String> map = new HashMap<>();
        for (FlowElement flowElement : flowElements) {
            //判断是否是连线
            if (flowElement instanceof SequenceFlow) {
                //两个对象
                SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                String ref = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                //当前和目标  流程ID 先组成一个数组
                map.put(ref + targetRef, sequenceFlow.getId());
            }
        }

        //获取流程实例 历史节点(全部)实际走过历史节点
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        //各个历史节点   两两组合 key
        Set<String> keyList = new HashSet<>();
        for (HistoricActivityInstance i : list) {
            for (HistoricActivityInstance j : list) {
                if (i != j) {
                    keyList.add(i.getActivityId() + j.getActivityId());
                }
            }
        }

        //高亮连线ID
        Set<String> highLine = new HashSet<>();
        keyList.forEach(s -> highLine.add(map.get(s)));

        //获取流程实例 历史节点（待办节点）
        List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .unfinished()
                .list();

        //需要移除的高亮连线
        Set<String> set = new HashSet<>();
        //待办高亮节点
        Set<String> waitingToDo = new HashSet<>();
        listUnFinished.forEach(s -> {
            waitingToDo.add(s.getActivityId());

            for (FlowElement flowElement : flowElements) {
                //判断是否是 用户节点
                if (flowElement instanceof UserTask) {
                    UserTask userTask = (UserTask) flowElement;

                    if (userTask.getId().equals(s.getActivityId())) {
                        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                        //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                        if (outgoingFlows != null && outgoingFlows.size() > 0) {
                            outgoingFlows.forEach(a -> {
                                if (a.getSourceRef().equals(s.getActivityId())) {
                                    set.add(a.getId());
                                }
                            });
                        }
                    }
                }
            }
        });

        highLine.removeAll(set);

        return highLine.stream().filter(item -> StringUtils.isNotEmpty(item)).collect(Collectors.toList());
    }
}
